<template>
  <!-- 吸顶效果 -->
  <div ref="stickyRef" :style="{ height: height + 'px', zIndex: zIndex }">
    <div :class="stickyClassName" :style="setSticky()">
      <slot />
    </div>
  </div>
</template>
<script setup lang="ts" name="Sticky">
export interface StickyProps {
  stickyTop?: number; // 距离顶部距离
  zIndex?: number; // 堆叠顺序
  stickyClassName?: string; // 吸顶效果的样式
}

// 接受父组件参数，配置默认值
const props = withDefaults(defineProps<StickyProps>(), {
  stickyTop: 0,
  zIndex: 9,
  stickyClassName: ''
});

// 是否有滚动到过元素定位的位置
let active = ref(false);
// 定位的方式
let position = ref('');
// 吸顶元素的宽
let width = ref();
// 吸顶元素的高
let height = ref();

let stickyRef = ref<any>(null);

onMounted(() => {
  // 设置元素的高
  height.value = stickyRef.value.getBoundingClientRect().height;
  window.addEventListener('scroll', handleScroll);
  window.addEventListener('resize', handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener('scroll', handleScroll);
  window.removeEventListener('resize', handleResize);
});

const setSticky = () => {
  const style: any = {
    top: active ? props.stickyTop + 'px' : '',
    zIndex: props.zIndex,
    position: position.value,
    width: width.value,
    height: height.value + 'px'
  };

  return style;
};

const sticky = () => {
  // 是否已滚动小于元素定位点 已滚动到过后不再重复设置

  if (active.value) {
    return;
  }
  // 设置定位方式
  position.value = 'fixed';
  // 标记已经小于定位点
  active.value = true;
  // 设置元素宽
  width.value = width.value + 'px';
};
const handleReset = () => {
  // 如果没有小于 元素定位设定点 那么不需要重置
  if (!active.value) {
    return;
  }
  reset();
};

// 取消元素设定的定位
const reset = () => {
  position.value = '';
  width.value = 'auto';
  // 标记定位元素离顶部的距离大于设定值
  active.value = false;
};

// 创建一个被节流的函数
const handleScroll = () => {
  // 滚动时动态设置元素宽
  const w = stickyRef.value.getBoundingClientRect().width;
  width.value = w;
  // 定位元素离顶部距离 小于设定值时 开启定位

  if (stickyRef.value.getBoundingClientRect().top < props.stickyTop) {
    sticky();
    return;
  }
  handleReset();
};

// 窗口大小改变
const handleResize = () => {
  // 当窗口大小改变时已经滚动到过小于元素定位点，那么重新设置一次元素宽度
  if (active.value) {
    width.value = stickyRef.value.getBoundingClientRect().width + 'px';
  }
};
</script>
